#include "Game.h"

//SGD Wrappers
#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "../SGD Wrappers/CSGD_DirectInput.h"
#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../SGD Wrappers/CSGD_XAudio2.h"

//Managers
#include "AudioManager.h"
#include "ProfileManager.h"
#include "ObjectManager.h"
#include "HelpInfoManager.h"
#include "BitmapFont.h"
#include "Camera.h"

//#include "IGameState.h"
#include "MainMenuState.h"
#include "TinyXMLDan.h"
#include "GamePlayState.h"
#include "GameCompleteState.h"
#include "IntroState.h"

#include <cassert>
#include "Time.h"

Game* Game::pInstance = nullptr;

/*static*/ Game* Game::GetInstance( void )
{
	// Allocate the static pointer if necessary
	if( pInstance == nullptr )
		pInstance = new Game;

	// Return the singleton
	return pInstance;
}


/*static*/ void Game::DeleteInstance( void )
{
	delete pInstance;
	pInstance = nullptr;
}

Game::Game(void)
{
	pD3D		= nullptr;
	pDI			= nullptr;
	pTM			= nullptr;
	pXA			= nullptr;
	
	//pFont		= nullptr;

	hasFocus = true;
	
	
	ScreenWidth	= 1;
	ScreenHeight= 1;
	IsWindowed	= true;
	
	pCurrState= nullptr;
}
Game::~Game(void)
{

}

void Game::Main(void)
{
	if(hasFocus)
	{
		//Check if we're ending the game via alt+f4
		if(Input())
			return;
		Update();
		Render();
	}
}


void Game::Begin(HWND hWnd, HINSTANCE hInstance, int nWidth, int nHeight,
					bool bIsWindowed )
{
	// Seed rand()
	srand((unsigned int)time(0));
	bRunning = TRUE;
	this->hInstance = hInstance;
	this->hWnd;

	//Store SGD Wrappers
	pD3D		= CSGD_Direct3D::GetInstance();
	pDI			= CSGD_DirectInput::GetInstance();
	pTM			= CSGD_TextureManager::GetInstance();
	pXA			= CSGD_XAudio2::GetInstance();

	//Store screensize
	ScreenWidth	= nWidth;
	ScreenHeight= nHeight;
	this->IsWindowed	= IsWindowed;

	//Initialize SGD Wrappers
	pD3D->Initialize( hWnd, ScreenWidth, ScreenHeight, IsWindowed, false );
	pDI->Initialize( hWnd, hInstance, DI_KEYBOARD | DI_JOYSTICKS, DI_JOYSTICKS );
	pDI->AcquireAll();
	pTM->Initialize( pD3D->GetDirect3DDevice(),	pD3D->GetSprite() );
	pXA->Initialize();

	logoImageID = pTM->LoadTexture(_T("Textures/Stress Test.png"));

	//TODO: Initialize local singletons
	//pFont->Initialize();
	objManager = ObjectManager::GetInstance();
	BitmapFont::GetInstance()->LoadFont("XML/fonts/xolonium.xml");
	ProfileManager::GetInstance()->loadProfiles();
	HelpInfoManager::GetInstance()->loadHelpInfo();
	AudioManager::GetInstance()->Initialize();


	CSGD_XAudio2::GetInstance()->MusicSetMasterVolume(	(ProfileManager::GetInstance()->getCurProfile().getMusicVolume() / 100.0f )
														* (ProfileManager::GetInstance()->getCurProfile().getMasterVolume()/100.0f));
	CSGD_XAudio2::GetInstance()->SFXSetMasterVolume(	(ProfileManager::GetInstance()->getCurProfile().getSFXVolume() / 100.0f)
														* (ProfileManager::GetInstance()->getCurProfile().getMasterVolume()/100.0f));
	//menuMusicID =pXA->MusicLoadSong(_T("resource/sounds/music/song_of_the_solitary_robot.xwm"));
	//AudioManager::GetInstance()->addMusic("menus",menuMusicID);
	int gameID = pXA->MusicLoadSong(_T("resource/sounds/music/space_sounds.xwm"));
	AudioManager::GetInstance()->addMusic("gameplay", gameID);
	gameID = pXA->MusicLoadSong(_T("resource/sounds/music/space_sounds_2.xwm"));
	AudioManager::GetInstance()->addMusic("gameplay2", gameID);
	gameID = pXA->MusicLoadSong(_T("resource/sounds/music/final_level.xwm"));
	AudioManager::GetInstance()->addMusic("menus", gameID);
	AudioManager::GetInstance()->startMusic("menus");

	gameID = pXA->SFXLoadSound(_T("resource/sounds/sound/fire.wav"));
	AudioManager::GetInstance()->addSFX("thermo_shoot", gameID);
	gameID = pXA->SFXLoadSound(_T("resource/sounds/sound/grapple_connect.wav"));
	AudioManager::GetInstance()->addSFX("grapple_attach", gameID);
	gameID = pXA->SFXLoadSound(_T("resource/sounds/sound/grapple_whoosh.wav"));
	AudioManager::GetInstance()->addSFX("grapple_activate", gameID);
	gameID = pXA->SFXLoadSound(_T("resource/sounds/sound/GateMove.wav"));
	AudioManager::GetInstance()->addSFX("gate_move", gameID);
	gameID = pXA->SFXLoadSound(_T("resource/sounds/sound/machine_fix.wav"));
	AudioManager::GetInstance()->addSFX("machine_fix", gameID);




	/*// Resize the window.
	int WINDOW_WIDTH = nWidth;
	int WINDOW_HEIGHT = nHeight;

	RECT desktop;

	const HWND hDesktop = GetDesktopWindow();

	GetWindowRect(hDesktop, &desktop);

	WINDOW_WIDTH = desktop.right - (desktop.bottom - WINDOW_HEIGHT);
	WINDOW_HEIGHT = desktop.bottom;

	SetWindowLongPtr(hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
	SetWindowPos(hWnd, HWND_TOP, ((desktop.right - desktop.left) >> 1) - (WINDOW_WIDTH >> 1), 0, WINDOW_WIDTH, WINDOW_HEIGHT, SWP_SHOWWINDOW);
	*/

	// Start in the Main Menu state
	ChangeState( IntroState::GetInstance() );
}

void Game::End(void)
{
	//Save everything!
	ProfileManager::GetInstance()->saveProfiles();

	// Exit the current state
	ChangeState( nullptr );

	//Clean up gameplay State possibly created by saveProfiles
	GamePlayState::DeleteInstance();
	GameCompleteState::DeleteInstance();
	//Camera::DeleteInstance();


	//Clean up local singletons
	ProfileManager::DeleteInstance();
	HelpInfoManager::DeleteInstance();
	BitmapFont::DeleteInstance();
	ObjectManager::DeleteInstance();

	//Shutdown SGD Wrappers
	pXA->Terminate();
	pTM->Terminate();
	pDI->Terminate();
	pD3D->Terminate();

	pD3D		= nullptr;
	pDI			= nullptr;
	pTM			= nullptr;
	pXA			= nullptr;

	ScreenWidth	= 1;
	ScreenHeight= 1;
	IsWindowed	= true;

	PostMessage(hWnd, WM_CLOSE, 0, 0);
}

//returns whether the game is ending or not
bool Game::Input(void)
{
	//Put this function call in input manager?
	pDI->ReadDevices();

	if((pDI->KeyPressed(DIK_LALT) || pDI->KeyPressed(DIK_RALT)) && pDI->KeyPressed(DIK_F4))
	{
		End();
		return true;
	}
	return false;
}
void Game::Update(void)
{
	// Update the audio
	pXA->Update();
	Time::GetInstance().Update();
	
	// Current state updates
	if(pCurrState != nullptr)
		pCurrState->Update(Time::GetInstance().DeltaTime());
}
void Game::Render(void)
{
	pD3D->Clear( D3DCOLOR_XRGB( 50, 50, 50 ) );	// Dark gray

	// Begin rendering
	pD3D->DeviceBegin();
	pD3D->SpriteBegin();

	//pTM->Draw(logoImageID, 0, 0); //  DELETE ME
	if(pCurrState != nullptr)
		pCurrState->Render();

	ostringstream oss;

	//oss << "FPS : " << Time::GetInstance().FPS();
	//BitmapFont::GetInstance()->Print(oss.str(), 5,5 ,0);
	
	pD3D->SpriteEnd();
	pD3D->DeviceEnd();
	
	// Present the backbuffer to the screen
	pD3D->Present();
}


void Game::ChangeState( GameState* pState )
{
	// Exit the current state (if any)
	if( pCurrState != nullptr )
		pCurrState->Exit();


	// Store the new state
	pCurrState = pState;


	// Enter the new state (if any)
	if( pCurrState != nullptr )
	{
		pCurrState->Enter();
	}
}

void Game::Shutdown()
{
	bRunning = FALSE;
}

void Game::PauseGame()
{
	hasFocus = false;
}

void Game::UnpauseGame()
{
	hasFocus = true;
}

void Game::SetIsWindowed(bool windowed)
{
	IsWindowed = windowed;

	RECT desktop;
	const HWND hDesktop = GetDesktopWindow();
	GetWindowRect(hDesktop, &desktop);

	if(windowed == true)
	{
		SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
		SetWindowPos(hWnd, HWND_TOP, ((desktop.right - desktop.left) >> 1) - (ScreenWidth >> 1), 0, ScreenWidth, ScreenHeight, SWP_SHOWWINDOW);
	}
	else
	{
		SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
		SetWindowPos(hWnd, HWND_TOP, ((desktop.right - desktop.left) >> 1) - (ScreenWidth >> 1), 0, ScreenWidth, ScreenHeight, SWP_SHOWWINDOW);
	}
}